import java.io.*;
import java.net.*;
import java.util.Scanner;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.logging.*;

public class Server {
    public static final Logger log = Logger.getLogger("Log");
    private static HashMap<String, String> serverConfigs = new HashMap<>();
    private static final String[] serverConfigName = { "监听端口", "数据库端口", "玩家刷新延迟" };
    private static Scanner keyin = new Scanner(System.in);
    /** 已连接用户数 */
    private static int numberOfConnectedUsers = 0;
    /** 已建立的Link的链表 */
    private static LinkedList<Link> linkList = new LinkedList<>();
    /** 准备好的玩家 */
    private static int numberOfReady = 0;
    /** 准备好的玩家的link链表 */
    private static LinkedList<Link> readyList = new LinkedList<>();
    /** 进入游戏的玩家 */
    private static int numberOfGo = 0;

    public static void main(String[] args) throws InterruptedException {
        /** SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST */
        log.setLevel(Level.INFO);// 设定日志等级
        initializeServerConfigs();// 初始化存储服务器配置的哈希表
        readServerConfigs();// 从文件[config.ini]读取服务器配置
        // Test.start();
        new Listens().start();// 开启监听功能 等待用户连接
        System.out.println("监听已开启.");
        while (true) {
            Test.ready();
            while (getNumberOfReady() < 4) {
                Thread.sleep(Integer.parseInt(serverConfigs.get("玩家刷新延迟")));
            }
            while (getNumberOfGo() < 4) {
                Thread.sleep(Integer.parseInt(serverConfigs.get("玩家刷新延迟")) >> 2);
            }
            System.out.println("准备人数达到四人.");
            System.out.println("玩家列表: " + readyList);
            for (int i = 0; i < 4; i++) {
                readyList.get(i).player = Game.currentPlayer();
                Game.toNextPlayer();
                readyList.get(i).player.setSocket(readyList.get(i).socket);
                readyList.get(i).player.setUserName(readyList.get(i).getUserName());
            }
            Test.start();
            // 游戏结束
            for (int i = 0; i < 4; i++) {
                Link l = readyList.get(i);
                synchronized (l) {
                    l.notifyAll();
                }
            }
            readyList.clear();
            resetNum();
        }
    }

    static class Listens extends Thread {
        @Override
        public void run() {
            try (ServerSocket svr = new ServerSocket(Integer.valueOf(serverConfigs.get("监听端口")))) {
                System.out.println("等待用户连接……");
                while (true) {
                    // 监听
                    Socket clt = svr.accept();
                    // 创建连接
                    Link newLink = new Link(clt);
                    newLink.start();
                    linkList.add(newLink);
                    userConnect();
                    System.out.println(clt.toString() + "连接." + " 当前连接用户数: " + numberOfConnectedUsers);
                    System.out.println("当前连接用户: " + linkList);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    static class Link extends Thread {
        private Socket socket;
        private Player player = null;
        private String userName;
        private String psw;

        public Link(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            boolean isReadied = false;
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter out = new PrintWriter(socket.getOutputStream());
                /**
                 * 处理登录与注册请求的代码块
                 */
                while (true) {
                    String str = in.readLine();
                    if (str.equals("<SignIn>")) {// 登录功能
                        userName = in.readLine();
                        System.out.println(this.socket + "用户名: " + userName);
                        psw = in.readLine();
                        System.out.println(this.socket + "密码: " + psw);
                        if (isMatched()) {
                            System.out.println(this.socket + "登录成功");
                            out.println("登录成功");
                            out.flush();
                            if (!in.readLine().equals("received")) {
                                throw new IOException(this.socket + "客户端未响应");
                            }
                            break;
                        } else {
                            System.out.println(this.socket + "登录失败");
                            out.println("登录失败");
                            out.flush();
                            if (!in.readLine().equals("received")) {
                                throw new IOException(this.socket + "客户端未响应");
                            }
                        }
                    } else if (str.equals("<Register>")) {// 注册功能
                        System.out.println(this.socket + "用户名: " + in.readLine());
                        System.out.println(this.socket + "密码: " + in.readLine());
                        out.println("注册成功");
                        out.flush();
                        if (!in.readLine().equals("received")) {
                            throw new IOException(this.socket + "客户端未响应");
                        }
                    } else {
                        throw new IOException(this.socket + "无法识别的命令[" + str + "].");
                    }
                }
                /**
                 * 登录成功后来到这里 处理匹配对局及查询战绩的业务
                 */
                while (true) {
                    String str = in.readLine();
                    System.out.println(socket.toString() + ": " + str);

                    if (str.equals("<Play>")) {
                        userReady();
                        readyList.add(this);
                        isReadied = true;
                        int number = 0;
                        do {
                            String str1 = in.readLine();
                            if (str1.equals("<number?>")) {
                                number = getNumberOfReady();
                                out.println(number);
                                out.flush();
                                if (!in.readLine().equals("received")) {
                                    throw new IOException(this.socket + "客户端未响应");
                                }
                            } else if (str1.equals("<overtime>")) {// 未达到四人 客户端超时
                                userUnReady();
                                readyList.remove(this);
                                isReadied = false;
                                break;
                            } else {
                                throw new IOException("客户端发送数据异常");
                            }
                        } while (number != 4);
                        if (number == 4 && in.readLine().equals("<go>")) {
                            out.println("OK");
                            out.flush();
                            if (!in.readLine().equals("received")) {
                                throw new IOException(this.socket + "客户端未响应");
                            }
                            addNumberOfGo();
                            synchronized (this) {
                                wait();
                            }
                        }
                    }
                    if (str.equals("<Bye>")) {
                        in.close();
                        out.close();
                        System.out.println(socket.toString() + "离开.");
                        userLeave();
                        linkList.remove(this);
                        break;
                    }
                }
            } catch (IOException e) {
                System.out.println(socket.toString() + "异常断线.");
                if (isReadied) {
                    userUnReady();
                    readyList.remove(this);
                    // isReadied = false;
                }
                userLeave();
                linkList.remove(this);
            } catch (InterruptedException e) {
                if (isReadied) {
                    userUnReady();
                    readyList.remove(this);
                    // isReadied = false;
                }
                userLeave();
                linkList.remove(this);
            }
        }

        /** 密码匹配 */
        public boolean isMatched() {
            return true;
        }

        public void setPlayer(Player player) {
            this.player = player;
        }

        public String getPsw() {
            return psw;
        }

        public String getUserName() {
            return userName;
        }

        @Override
        public String toString() {
            return socket.getInetAddress().toString() + ':' + socket.getPort();
        }
    }

    /** 初始化存储服务器配置的哈希表 */
    private static void initializeServerConfigs() {
        int numberOfConfig = serverConfigName.length;
        for (int i = 0; i < numberOfConfig; i++) {
            serverConfigs.put(serverConfigName[i], null);
        }
    }

    /** 从文件[config.ini]读取服务器配置 */
    private static void readServerConfigs() {
        try (Scanner configScanner = new Scanner(new File(".\\config.ini"));) {
            System.out.println("读取配置文件……");
            while (configScanner.hasNextLine()) {
                String input = configScanner.nextLine();
                String name = input.split("=", 2)[0];
                String value = input.split("=", 2)[1];
                if (serverConfigs.containsKey(name)) {
                    serverConfigs.replace(name, value);
                } else {
                    System.err.println("\t参数[" + name + "]无效!");
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到[config.ini]. 请手动输入参数.");
            int numberOfConfig = serverConfigName.length;
            for (int i = 0; i < numberOfConfig; i++) {
                System.out.print("[" + serverConfigName[i] + "]: ");
                serverConfigs.put(serverConfigName[i], keyin.nextLine());
            }
        }
        System.out.println("服务器配置 = " + serverConfigs);
    }

    private static synchronized void userConnect() {
        numberOfConnectedUsers++;
    }

    private static synchronized void userLeave() {
        numberOfConnectedUsers--;
    }

    private static synchronized void userReady() {
        numberOfReady++;
    }

    private static synchronized void userUnReady() {
        numberOfReady--;
    }

    private static synchronized int getNumberOfReady() {
        return numberOfReady;
    }

    public static synchronized int getNumberOfGo() {
        return numberOfGo;
    }

    public static synchronized void addNumberOfGo() {
        numberOfGo++;
    }

    public static void resetNum() {
        numberOfGo = 0;
        numberOfReady = 0;
    }
}
